<!--
 * @Author: xudj
 * @Date: 2021-11-17 10:30:48
 * @LastEditTime: 2021-11-17 16:45:07
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \fd-analysis-industry-map\src\components\draw\drawBorder.vue
-->
<template>
  <div class="draw_border" id="draw_border">
    <div class="draw_content" id="containerChart"></div>
    <div id="tooltip" class="tooltiptext tooltiptext1">
      <p @click="delNode">删除</p>
    </div>
  </div>
</template>
<script>
import { Graph, Shape, FunctionExt } from '@antv/x6'
import bus from './utils/bus'

export default {
  data() {
    return {
      graph: '',
      type: 'grid',
      selectCell: '',
      ids: null,
      defalutName: '',
      insterIndex: 0,
      timer: null,
      show: '',
      rightCell: null,
      haveChild: false,
      list: [],
      isDetail: false,
      mapInfo: {
        mapJson: null
      },
      connectEdgeType: {
        // 连线方式
        connector: 'normal',
        router: {
          name: 'manhattan'
        }
      }
    }
  },
  /* eslint-disable */
  mounted() {
    // 拖拽节点没监听有没有画布，没有则渲染画布
    bus.$on('drawView', () => {
      this.drawShow()
    })

    this.getMapJson()
  },
  beforeDestroy() {
    bus.$off('drawView')
  },
  props: {
    view: {
      type: Boolean,
      default: false
    },
    map_data: {
      type: Object
    }
  },
  watch: {},
  computed: {},
  methods: {
    drawShow() {
      this.$emit('update:view', true)
    },
    getMapJson() {
      const that = this
      this.$nextTick(() => {
        that.initX6()
      })
    },
    delNode() {
      this.delCell(this.rightCell)
    },
    initX6() {
      const _that = this
      this.graph = new Graph({
        container: document.getElementById('containerChart'),
        width: '100%',
        height: '100%',
        history: true,
        embedding: {
          enabled: true,
          findParent({ node }) {
            let canIsinter = !(node.attrs.body.types == 'bigNode')
            const bbox = node.getBBox()
            const status = _that.isNoship(node) //节点没有链接线时返回true，节点有链接线且是有父级视图返回父级视图节点对象，节点有链接线且没有父级视图返回false
            return this.getNodes().filter((node) => {
              const data = node.getData()
              if (data && data.parent && status && canIsinter) {
                const targetBBox = node.getBBox()
                if (typeof status === 'boolean' || status.id === node.id) {
                  return bbox.isIntersectWithRect(targetBBox)
                }
              }
              return false
            })
          }
        },
        panning: {
          enabled: true
        }, // 画布拖动
        selecting: {
          enabled: true,
          multiple: false //
        },
        snapline: true, // 对齐线
        background: {
          color: '#fff'
        },
        interacting: {
          edgeLabelMovable: true, // 边的标签是否可以被移动
          nodeMovable: this.$route.path !== '/MapDeatail'
        },
        connecting: {
          // 节点连接
          anchor: 'center',
          connectionPoint: 'anchor',
          allowBlank: false,
          allowLoop: false,
          allowMulti: false,
          allowNode: false,
          allowPort: this.$route.path !== '/MapDeatail',
          snap: true,
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: '#CCCCCC',
                  strokeWidth: 1,
                  targetMarker: {
                    name: 'classic',
                    size: 8
                  },
                  strokeDasharray: 5, // 虚线
                  style: {
                    animation: 'ant-line 30s infinite linear'
                  }
                }
              },
              label: {
                text: ''
              },
              connector: _that.connectEdgeType.connector,
              router: {
                name: _that.connectEdgeType.router.name || ''
              },
              zIndex: 0
            })
          }
        },
        highlighting: {
          magnetAvailable: {
            name: 'stroke',
            args: {
              padding: 4,
              attrs: {
                strokeWidth: 4,
                stroke: '#6a6c8a'
              }
            }
          }
        }
      })
      const map_data = this.mapInfo.mapJson || this.map_data || {}
      this.graph.fromJSON(map_data)
      // 预览编辑时候，初始化隐藏线的拖拽工具，避免保存时已经存在导致不可移除
      this.graph.getEdges().forEach((items) => {
        items.removeTools()
      })
      if (Object.keys(map_data).length > 0) {
        const container1 = document.getElementById('containerChart')
        const ports1 = container1.querySelectorAll('.x6-port-body')
        this.showPorts(ports1, false)
      }
      if (this.$route.path !== '/MapDeatail') {
        const _this = this
        document.onkeydown = function () {
          const key = window.event.keyCode
          if (key === 46) {
            _this.delCell(_this.selectCell)
            _this.type = 'grid'
            _this.selectCell = null
            bus.$emit('selectionNode', _this.type)
          }
        }

        let ctrlPressed = false
        const embedPadding = 20

        this.graph.on('node:embedding', ({ e }) => {
          ctrlPressed = e.metaKey || e.ctrlKey
        })

        this.graph.on('node:embedded', () => {
          ctrlPressed = false
        })

        this.graph.on('node:change:size', ({ node, options }) => {
          if (options.skipParentHandler) {
            return
          }
          const children = node.getChildren()
          if (children && children.length) {
            node.prop('originSize', node.getSize())
          }
        })

        this.graph.on('node:change:position', ({ node, options }) => {
          if (options.skipParentHandler || ctrlPressed) {
            return
          }
          const children = node.getChildren()
          if (children && children.length) {
            node.prop('originPosition', node.getPosition())
          }

          const parent = node.getParent()
          if (parent && parent.isNode()) {
            let originSize = parent.prop('originSize')
            if (originSize == null) {
              originSize = parent.getSize()
              parent.prop('originSize', originSize)
            }

            let originPosition = parent.prop('originPosition')
            if (originPosition == null) {
              originPosition = parent.getPosition()
              parent.prop('originPosition', originPosition)
            }

            let x = originPosition.x
            let y = originPosition.y
            let cornerX = originPosition.x + originSize.width
            let cornerY = originPosition.y + originSize.height
            let hasChange = false

            const children = parent.getChildren()
            if (children) {
              children.forEach((child) => {
                const bbox = child.getBBox().inflate(embedPadding)
                const corner = bbox.getCorner()

                if (bbox.x < x) {
                  x = bbox.x
                  hasChange = true
                }

                if (bbox.y < y) {
                  y = bbox.y
                  hasChange = true
                }

                if (corner.x > cornerX) {
                  cornerX = corner.x
                  hasChange = true
                }

                if (corner.y > cornerY) {
                  cornerY = corner.y
                  hasChange = true
                }
              })
            }

            if (hasChange) {
              parent.prop(
                {
                  position: { x, y },
                  size: { width: cornerX - x, height: cornerY - y }
                },
                { skipParentHandler: true }
              )
            }
          }
        })

        //右键需要处理子图节点和普通节点
        this.graph.on('cell:contextmenu', ({ cell, x, y }) => {
          if (cell.shape === 'rect') {
            this.haveChild = !!cell.attrs.body.types //是否是子图
          } else {
            this.haveChild = false
          }
          const p1 = this.graph.localToGraph(x, y)
          var text = document.getElementById('tooltip')
          text.style.display = 'block'
          text.style.left = p1.x.toString() + 'px'
          text.style.top = p1.y.toString() + 'px'
          this.rightCell = cell
        })
        this.graph.on(
          'node:mouseenter',
          FunctionExt.debounce(({ e, cell, view }) => {
            cell.attr('body/stroke', 'rgba(20, 146, 255, 1)')
            const container = view.container
            const ports = container.querySelectorAll('.x6-port-body')
            this.showPorts(ports, true)
          }),
          500
        )
        this.graph.history.on('change', () => {
          const canUndo = this.graph.history.canUndo()
          const canRedo = this.graph.history.canRedo()
          bus.$emit('canDo', { canUndo, canRedo })
        })
        this.graph.on('node:mousemove', ({ cell }) => {
          // 当前拖动的节点和选中的节点是否是同一个
          if (cell === this.selectCell) {
            // 如果是同一个节点的话，改变position的值修改右边节点属性的x，y
            this.changePosition(cell)
          }
        })
        //线链接事件监听，判断一个节点是否链接了父级节点,如果没有父级节点，直接选中父子关系
        this.graph.on('edge:connected', ({ isNew, edge }) => {
          if (isNew) {
            //节点与子节点的连线
            let sourceCellFahter = this.graph.getCellById(edge.source.cell).getParentId()
            let targetCellFahter = this.graph.getCellById(edge.target.cell).getParentId()
            if (sourceCellFahter != targetCellFahter) {
              this.$Message.error('节点不允许直接与子图节点链接')
              this.graph.removeNode(edge)
              return
            }
            //子图连线

            if (this.graph.getCellById(edge.source.cell).attrs.body.types) {
              this.$Message.error('子图节点不允许与其他节点链接')
              this.graph.removeNode(edge)
              return
            }

            //父子连接线
            let edge_list = this.graph.getEdges().filter((item) => {
              return item.attrs.hasOwnProperty('common') && item.attrs.common.line_type == 1
            })
            //判断父子链接线中有没有去向的id跟新生成线的id相同 来判断该线生成了第二个父级
            let index = edge_list.findIndex((item) => item.target.cell === edge.target.cell)
            if (index > -1) {
              this.$Message.error('父子关系中，子节点不允许出现多个父节点！')
              this.graph.removeNode(edge)
              return
            }
            //判断连线是否会闭合
            let status = this.checkClose(edge, edge_list)
            if (!status) {
              this.graph.removeNode(edge)
              this.$Message.error('父子关系中，不允许出现闭环状！')
              return
            }
            bus.$emit('selectionNode', 'edge')
            //默认选中父节点
            edge.attr('common/line_type', '1')
            edge.attr('line/stroke', '#6DD993')
            edge.attr('line/strokeDasharray', 0)
            this.graph.resetSelection(edge)
          }
        })
        //创建节点时候 默认选中对应的节点
        this.graph.on('node:added', ({ cell }) => {
          if (cell.attrs.body.types) {
            cell.setZIndex(0)
            cell.setData({ parent: true })
          }
          bus.$emit('selectionNode', 'rect')
          this.graph.resetSelection(cell)
        })
        this.graph.on('edge:added', ({}) => {
          const container = document.getElementById('containerChart')
          const ports = container.querySelectorAll('.x6-port-body')
          this.showPorts(ports, true)
        })

        // 鼠标移出节点移除连接庄
        this.graph.on('node:mouseleave', ({ cell }) => {
          const container = document.getElementById('containerChart')
          const ports = container.querySelectorAll('.x6-port-body')
          this.showPorts(ports, false)
          if (cell !== this.selectCell) {
            if (cell.attrs.body.types) {
              cell.attr('body/stroke', 'rgba(20, 146, 255, 0.5)')
            } else {
              cell.attr('body/stroke', '#D8D8D8')
            }
          }
        })
      }
      //拖动画布，定位不准 取消弹出框
      this.graph.on('translate', ({ tx, ty }) => {
        this.resetRight()
        var text = document.getElementById('tooltipText')
        text.style.display = 'none'
      })
      // 选中状态判断右侧数据栏显示
      this.graph.on('blank:click', () => {
        this.type = 'grid'
        this.selectCell = null
        this.rightCell = null
        var text = document.getElementById('tooltip')
        text.style.display = 'none'
        bus.$emit('selectionNode', this.type)
      })
      this.graph.on(
        'cell:mousemove',
        FunctionExt.debounce(({ cell }) => {
          var text = document.getElementById('tooltip')
          text.style.display = 'none'
        }),
        500
      )

      this.graph.on('cell:click', ({ cell, view }) => {
        this.type = cell.isNode() ? (!cell.attrs.body.hasOwnProperty('types') || !cell.attrs.body.types ? 'rect' : 'grid') : 'edge'
        bus.$emit('selectionNode', this.type)
      })
      // 选择变化
      this.graph.on('selection:changed', (args) => {
        // 当前选中的节点数组
        args.added.forEach((cell) => {
          this.selectCell = cell
          if (cell.isNode()) {
            // 选中是rect节点颜色改变
            if (!cell.attrs.body.types) {
              cell.attr('body/fill', 'rgba(20, 146, 255, 0.05)')
              cell.attr('body/stroke', 'rgba(20, 146, 255, 1)')
            } else {
              cell.attr('body/fill', 'rgba(20, 146, 255, 0.05)')
              cell.attr('body/stroke', '#1492FF')
              bus.$emit('selectionNode', 'grid')
            }
          } else {
            if (this.$route.path !== '/MapDeatail') {
              cell.addTools([
                {
                  name: 'vertices',
                  args: {
                    padding: 4,
                    attrs: {
                      strokeWidth: 0.1,
                      stroke: '#2d8cf0',
                      fill: '#ffffff'
                    }
                  }
                }
              ])
            }
          }
          // 初始化右边节点数据
          if ((cell.isNode() && !cell.attrs.body.types) || !cell.isNode()) {
            bus.$emit('viewRightJson', cell)
          }
        })

        // 当前取消的节点数组
        args.removed.forEach((cell) => {
          if (cell.isNode()) {
            // 取消节点rect节点颜色改变
            if (!cell.attrs.body.types) {
              cell.attr('body/fill', '#fff')
              cell.attr('body/stroke', '#D8D8D8')
            } else {
              cell.attr('body/fill', 'rgba(20, 146, 255, 0.05)')
              cell.attr('body/stroke', 'rgba(20, 146, 255, 0.5)')
            }
          } else {
            cell.removeTools()
          }
        })
      })
      bus.$emit('graphListen', this.graph)
    },
    //查看节点是否有链接线
    isNoship(items) {
      let edge_list = this.graph.getEdges().filter((item) => {
        return item.attrs.hasOwnProperty('common') && item.attrs.common.line_type == 1
      })
      let index = edge_list.find((node) => {
        return node.target.cell === items.id || node.source.cell === items.id
      })
      return !index || index.parent
    },
    delCell(cell) {
      if (cell) {
        this.graph.removeNode(cell)
      }
    },
    showPorts(ports, show) {
      for (let i = 0, len = ports.length; i < len; i += 1) {
        ports[i].style.visibility = show ? 'visible' : 'hidden'
      }
    },
    //链接线是否会闭合
    checkClose(edge, edge_list) {
      let index = edge_list.findIndex((item) => {
        return item.target.cell === edge.source.cell
      })
      let index1 = edge_list.findIndex((item) => {
        return item.source.cell === edge.target.cell
      })
      //如果线的来源没有父级，去向没有子级，就不用考虑闭合
      if (index === -1 || index1 === -1) {
        return true
      } else {
        //递归查找到最上级的父元素
        let fatherId = this.deepFather(edge.source.cell, edge_list)
        return fatherId !== edge.target.cell
      }
    },
    deepFather(sourceId, edge_list) {
      let node
      console.log(edge_list)
      node = edge_list.find((item) => {
        return item.target.cell === sourceId
      })
      if (node) {
        return this.deepFather(node.source.cell, edge_list)
      } else {
        return sourceId
      }
    },
    changePosition(cell) {
      if (this.timer) {
        clearTimeout(this.timer)
      }
      this.timer = setTimeout(() => {
        // 更新右侧数据
        bus.$emit('viewRightJson', cell)
      }, 300)
    }
  }
}
</script>
<style lang="less" scoped>
.draw_border {
  position: relative;
  height: 400px;
  .tooltiptext {
    min-width: 328px;
    background: #ffffff;
    box-shadow: 0px 0px 6px 6px rgba(0, 0, 0, 0.14);
    padding: 16px;
    position: absolute;
    border-radius: 4px;
    z-index: 999;
    display: none;
    line-height: 40px;
    .ivu-col-span-12 {
      margin: 0 !important;
    }
    .tooltip-arrow {
      position: absolute;
      width: 0;
      height: 0;
      border-color: transparent;
      border-style: solid;
      top: -6px;
      left: 0.5px;
      right: 0;
      margin: 0 auto;
      border-width: 0 6px 6px;
      border-bottom-color: #fff;
    }
  }
  .tooltiptext1 {
    padding: 8px 0;
    min-width: 100px;
    .tooltip-arrow {
      margin-left: 0px;
    }
    p {
      cursor: pointer;
      padding: 0px 0 0 16px;
      font-size: 14px;
      line-height: 32px;
    }
    p:hover {
      background-color: #edf4ff;
      font-size: 14px;
      color: #1492ff;
    }
  }
  .tip_content,
  .draw_content {
    width: 100%;
    height: 100%;
  }
  .tip_content {
    background-color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    .tip_item {
      text-align: center;
      margin-left: 72px;
      position: relative;
      .lines_bar {
        width: 259px;
        height: 2px;
        background: #cccccc;
        position: absolute;
        left: 136px;
        top: 10px;
      }
      .daius {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: #cccccc;
        border-radius: 50%;
      }
      .title {
        font-size: 16px;
        font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
        font-weight: bold;
        color: #cccccc;
      }
      .desc {
        font-size: 14px;
        font-family: MicrosoftYaHeiUI;
        color: #cccccc;
      }
    }
    .tip_item:nth-child(1) {
      margin-left: 0;
    }
  }
  .line_group {
    position: absolute;
    bottom: 24px;
    left: 24px;
    z-index: 0;
    .bar {
      display: inline-block;
      width: 14px;
      height: 2px;
      margin-right: 8px;
      position: relative;
      top: -4px;
    }
    .defalut_bar {
      background-color: #ccc;
    }
    .father_childBar {
      background-color: #6dd993;
    }
    .line_bar {
      background-color: #1492ff;
    }
    span {
      font-size: 12px;
      color: #333333;
    }
  }
}
</style>
